home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Snippets / AOCE / DragBusinessCard / SimpleDrag.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-11  |  38.9 KB  |  1,551 lines  |  [TEXT/MPS ]

  1. /*
  2.  *  SimpleDrag.c     Drag Manager sample program
  3.  *
  4.  *  SimpleDrag lets the user make one or more picture windows
  5.  *  Pictures can be dragged among (amongst?) windows and from
  6.  *  PICT files
  7.  *
  8.  *  All code using the Drag Manager is at the beginning of this
  9.  *  file (darn near, anyway)
  10.  *
  11.  *  v 1.0d4  8/93 Greg Robbins
  12.  *
  13.  *    93/9 dj final touch up to match final interfaces:
  14.  *        Changed DragGetXXX -> GetDragXXX
  15.  *        Changed DragFlags -> DragAttributes and some flag names changed
  16.  *        Eliminated last parameter to GetFlavorData to match prototype
  17.  *        
  18.  */
  19.  
  20.  
  21. #include "SimpleDrag.h"     // nothing interesting is in SimpleDrag.h
  22.  
  23. // menu constants
  24. #define kAppleMenuID 1
  25. #define kAboutMenuItem 1
  26. #define kFileMenuID 2
  27. #define kNewMenuItem 1
  28. #define kOpenMenuItem 2
  29. #define kCloseMenuItem 3
  30. #define kQuitMenuItem 5
  31.  
  32.  
  33.  
  34. // general global variables
  35.  
  36. Boolean            gQuitFlag;    // true when the app should exit the main event loop
  37.  
  38. Boolean            gHasColorQuickdrawFlag; // Gestalt info
  39.  
  40. MenuHandle        gAppleMenuHandle, gFileMenuHandle;
  41. unsigned short    gWindowCounter;
  42.  
  43. // data structure for each window
  44.  
  45. typedef struct WindowData {
  46.     PicHandle windowPic;
  47. };
  48. typedef struct WindowData WindowData, *WindowDataPtr, **WindowDataHandle;
  49.  
  50.  
  51. // global data for my Drag Manager handlers
  52.  
  53. typedef struct DragHandlerGlobals {
  54.     Boolean acceptableDragFlag;
  55.     Boolean windowIsHilightedFlag;
  56. };
  57. typedef struct DragHandlerGlobals
  58.     DragHandlerGlobals, *DragHandlerGlobalsPtr;
  59.  
  60. DragHandlerGlobals gDragHandlerGlobals;
  61.  
  62.  
  63. /**************************************************************/
  64.  
  65. /*    This is the "aoce PhoneNumber" attribute type definition */
  66.  
  67. AttributeType gWorkPhoneNumber =     {smRoman,
  68.                                     16,
  69.                                     {"aoce PhoneNumber"}
  70.                                     };
  71. Str255                 displayStr;                                    
  72. #define MaxCharsPerLine        30
  73.  
  74. DSSpec                gTheCard;
  75. AuthIdentity        gIdentity;
  76.  
  77.  
  78. /***************************************************
  79.  *    Drag support routines
  80.  *
  81.  *    These are the installed drag handler routines
  82.  *    and supporting functions
  83.  ***************************************************/
  84.  
  85. // InstallDragHandlers attaches my tracking and receive handlers to
  86. // one of the application's windows
  87.  
  88. OSErr InstallDragHandlers(WindowPtr theWindow)
  89. {
  90.     // install our tracking and receive handlers for the window
  91.     
  92.     OSErr retCode;
  93.     
  94.     retCode = InstallTrackingHandler(MyTrackingHandler, theWindow, nil);
  95.  
  96.     if (retCode == noErr) {
  97.         retCode = InstallReceiveHandler(MyReceiveHandler, theWindow, nil);
  98.         if (retCode != noErr)
  99.             (void) RemoveTrackingHandler(MyTrackingHandler, theWindow);
  100.     }
  101.     
  102.     return retCode;
  103. }
  104.  
  105.  
  106. // RemoveDragHandlers removes my tracking and receive handlers from
  107. // one of the application's windows (prior to the window's disposal,
  108. // presumably)
  109.  
  110. void RemoveDragHandlers(WindowPtr theWindow)
  111. {
  112.     RemoveReceiveHandler(MyReceiveHandler, theWindow);
  113.     RemoveTrackingHandler(MyTrackingHandler, theWindow);
  114. }
  115.  
  116.  
  117. // MouseInContentRgn returns true if the current mouse is in the content
  118. // area of the window (but not necessarily in the visible rgn)
  119.  
  120. Boolean MouseIsInContentRgn(DragReference theDrag, WindowPtr theWindow)
  121. {
  122.     Point mousePt;
  123.     
  124.     (void) GetDragMouse(theDrag, &mousePt, nil);
  125.     return PtInRgn(mousePt, ((WindowPeek) theWindow)->contRgn);
  126. }
  127.  
  128.  
  129. // DragItemsAreAcceptable returns true if the contents (data) of
  130. // the drag are acceptable by a window of this application
  131. //
  132. // DragItemsAreAcceptable is called by the tracking and 
  133. // receive handlers
  134.  
  135. Boolean DragItemsAreAcceptable(DragReference theDrag)
  136. {
  137.     OSErr            retCode;
  138.     unsigned short    totalItems;
  139.     ItemReference    itemRef;
  140.     Boolean            acceptableFlag;
  141.     HFSFlavor         currHFSFlavor;
  142.     Size            flavorDataSize;
  143.     FlavorFlags        currFlavorFlags;
  144.     
  145.     acceptableFlag = false;
  146.  
  147.     // this app can only accept the drag of a single item
  148.     retCode = CountDragItems(theDrag, &totalItems);
  149.     if (retCode == noErr && totalItems == 1) {
  150.     
  151.         // get the reference number of the dragged item
  152.         retCode = GetDragItemReferenceNumber(theDrag, 1, &itemRef);
  153.         if (retCode == noErr) {
  154.             
  155.             // use GetFlavorFlags to check on flavor existence of PICT data
  156.             // without forcing translation
  157.             
  158.             retCode = GetFlavorFlags (theDrag, itemRef, 'PICT', &currFlavorFlags);
  159.             if (retCode == noErr)
  160.                 acceptableFlag = true;
  161.             // Drags from any AOCE Catalog are ok
  162.             else if ( retCode = GetFlavorFlags (theDrag, itemRef, flavorTypeDirectory, &currFlavorFlags) == noErr )
  163.                 acceptableFlag = true;
  164.     
  165.             else {
  166.             
  167.                 // check if the item is a file spec for a PICT file or an AOCE business card
  168.                 flavorDataSize = sizeof(HFSFlavor);
  169.                 retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, &currHFSFlavor,
  170.                     &flavorDataSize, 0);
  171.                 // Is it a business card?
  172.                 if (retCode == noErr && (currHFSFlavor.fileType == 'PICT' ||
  173.                                         currHFSFlavor.fileType == kBusinessCardFileType)) 
  174.                     acceptableFlag = true;
  175.             }
  176.         }
  177.     }
  178.     return acceptableFlag;
  179. }
  180.  
  181.  
  182. // DragIsNotInSourceWindow returns true if the drag in progress
  183. // is not in the same window it originated in
  184. //
  185. // DragIsNotInSourceWindow is called by the tracking and receive handlers
  186. //
  187. // Note that, if this application allowed items to be dragged within
  188. // its windows, this function would not be appropriate.
  189. // Instead, hilighting would probably occur in the source window
  190. // when the dragHasLeftSourceWindow flag is set, and the receive
  191. // handler wouldn't check this at all
  192.  
  193. Boolean DragIsNotInSourceWindow(DragReference theDrag)
  194. {
  195.     DragAttributes currDragFlags;
  196.     
  197.     (void) GetDragAttributes(theDrag, &currDragFlags);
  198.     return ((currDragFlags & dragInsideSenderWindow) == 0);
  199. }
  200.  
  201.  
  202. // MyTrackingHandler is called by the drag manager whenever a drag is
  203. // over one of the application's windows
  204. //
  205. // upon entry, the current port has been set to theWindow by the Drag Manager
  206.  
  207. pascal OSErr MyTrackingHandler(DragTrackingMessage theMessage, WindowPtr theWindow,
  208.     void *handlerRefCon, DragReference theDrag)
  209. {
  210. #pragma unused (handlerRefCon)
  211.  
  212.     RgnHandle    tempRgn;
  213.     Boolean        mouseInContentFlag;
  214.     OSErr        retCode;
  215.     
  216.     retCode = noErr;
  217.     
  218.     switch (theMessage) {
  219.     
  220.         case dragTrackingEnterHandler:
  221.             
  222.             // determine if the items are acceptable and store
  223.             // that flag in the globals, plus reset the
  224.             // hilighted global flag
  225.             
  226.             gDragHandlerGlobals.acceptableDragFlag = 
  227.                 DragItemsAreAcceptable(theDrag);
  228.             gDragHandlerGlobals.windowIsHilightedFlag = false;
  229.             
  230.             // let the drag manager know if we can't accept this drag
  231.             if (!gDragHandlerGlobals.acceptableDragFlag)
  232.                 retCode = dragNotAcceptedErr;
  233.             break;
  234.             
  235.         case dragTrackingEnterWindow: 
  236.         case dragTrackingInWindow:
  237.         case dragTrackingLeaveWindow:
  238.             
  239.             // highlighting of the window during a drag is done
  240.             // here.  Do it only if we can accept these items
  241.             // and we're not in the source window...
  242.             
  243.             if (gDragHandlerGlobals.acceptableDragFlag &&
  244.                 DragIsNotInSourceWindow(theDrag)) {
  245.                 
  246.                 // unless the mouse is leaving the visible area of the
  247.                 // window, check if it's in the window's content region
  248.                 
  249.                 if (theMessage == dragTrackingLeaveWindow)
  250.                     mouseInContentFlag = false;
  251.  
  252.                 else
  253.                     mouseInContentFlag = MouseIsInContentRgn(theDrag, theWindow);
  254.                 
  255.                 // if the mouse is in the content area and the window
  256.                 // is not yet hilighted, then do the hilighting
  257.                 
  258.                 if (mouseInContentFlag &&
  259.                     !gDragHandlerGlobals.windowIsHilightedFlag) {
  260.                     
  261.                     // set the proper clip
  262.                     ClipRect(&theWindow->portRect);
  263.                     
  264.                     // make a region bordering the window content
  265.                     tempRgn = NewRgn();
  266.                     RectRgn(tempRgn, &theWindow->portRect);
  267.                     
  268.                     // draw the hilight
  269.                     if (ShowDragHilite(theDrag, tempRgn, true) == noErr)
  270.                     
  271.                         // remember that hilighting is now on
  272.                         gDragHandlerGlobals.windowIsHilightedFlag = true;                    
  273.                     
  274.                     // free up the region
  275.                     DisposeRgn(tempRgn);
  276.                 }
  277.                 
  278.                 // else if the mouse is not in the content region
  279.                 // and the window is hilighted, erase the hilight
  280.                 
  281.                 else if (!mouseInContentFlag &&
  282.                     gDragHandlerGlobals.windowIsHilightedFlag) {
  283.                     
  284.                     // set the proper clip
  285.                     ClipRect(&theWindow->portRect);
  286.                     
  287.                     // erase the hilight and restore the port
  288.                     if (HideDragHilite(theDrag) == noErr)
  289.                     
  290.                         // remember that hilighting is now off
  291.                         gDragHandlerGlobals.windowIsHilightedFlag = false;
  292.                 }
  293.             }
  294.             break;
  295.  
  296.         // do nothing for the leaveHandler message
  297.         case dragTrackingLeaveHandler:
  298.             break;
  299.         
  300.         // let the drag manager know if we didn't recognize the message
  301.         default:
  302.             retCode = paramErr;
  303.     }
  304.     
  305.     return retCode;
  306. }
  307.  
  308.  
  309.  
  310. /*****************************************************************************
  311.  * ClearMemory
  312.  * This is a utility function that clears a block of memory. It isn't very
  313.  * efficient. It us normally called by executing the CLEAR macro which expands
  314.  * CLEAR(thing) to
  315.  *        ClearMemory(&thing, sizeof thing);
  316.  *****************************************************************************/
  317. void
  318. ClearMemory(
  319.         void                *recordPtr,
  320.         register Size        recordSize
  321.     )
  322. {
  323.         register char        *rp;
  324.         
  325.         rp = (char *) recordPtr;
  326.         while (recordSize > 0) {
  327.             *rp++ = 0;
  328.             --recordSize;
  329.         }
  330. }
  331.  
  332.  
  333.  
  334.  
  335. /*****************************************************************
  336.  *    GetRecordID
  337.  *
  338.  *
  339.  *****************************************************************/
  340.  
  341. OSErr GetRecordID( FSSpecPtr     fsspec,
  342.                    RecordIDPtr   ridPtr,
  343.                    RStringPtr    recordType)
  344. {
  345. OSErr             err;
  346. DirParamBlock     pb;
  347.  
  348.     pb.openPersonalDirectoryPB.fsSpec = fsspec;
  349.     pb.openPersonalDirectoryPB.accessRequested = fsRdPerm;
  350.      /* get reference number for Business Card */
  351.     err = DirOpenPersonalDirectory(&pb);
  352.     if (err == noErr)
  353.     {
  354.        err = DoEnumerateGet( pb.openPersonalDirectoryPB.dsRefNum, 
  355.                              (long)&ridPtr->local,
  356.                              recordType,
  357.                              gIdentity);
  358.        if (err == noErr)
  359.        {
  360.           pb.getNameAndTypePB.identity = 0;
  361.           pb.getNameAndTypePB.aRecord = ridPtr;
  362.           err = DirGetNameAndType (&pb, false);
  363.           if (err == noErr)
  364.           {
  365.              pb.makePersonalDirectoryRLIPB.fromFSSpec = fsspec;
  366.              pb.makePersonalDirectoryRLIPB.pRLIBufferSize = kRLIMaxBytes;
  367.              pb.makePersonalDirectoryRLIPB.pRLI = ridPtr->rli;
  368.              err = DirMakePersonalDirectoryRLI(&pb);
  369.            }
  370.         }
  371.         DirClosePersonalDirectory(&pb);
  372.      }
  373.  
  374.  return (err);
  375. }
  376.  
  377.  
  378.  
  379. // MyReceiveHandler is called by the drag manager whenever a drag is
  380. // ends on one of the application's windows
  381.  
  382. pascal OSErr MyReceiveHandler(WindowPtr theWindow, void *handlerRefCon, 
  383.         DragReference theDrag)
  384. {
  385. #pragma unused (handlerRefCon)
  386.     ItemReference        itemRef;
  387.     Size                dataSize;
  388.     Handle                tempHandle;
  389.     HFSFlavor            theHFSFlavor;
  390.     Boolean                dataObtainedFlag;
  391.     OSErr                retCode;
  392. //    AttributeTypePtr     theAttrType;
  393.     PackedDSSpec        packedDSSpec;
  394.     Attribute            attribute;
  395.     DSSpec                 dsspec;
  396.     RecordID             rid;
  397.     short                 dsRefNum;
  398.     HFSFlavor            hfsData;
  399.     RString             name,type;
  400.     PackedRLI           packedRLI;
  401.     LocalRecordID       localRID;
  402.     CreationID          cid;
  403.  
  404.     
  405.     dataObtainedFlag = false;
  406.     if (!DragItemsAreAcceptable(theDrag) ||
  407.             !MouseIsInContentRgn(theDrag, theWindow) ||
  408.             !DragIsNotInSourceWindow(theDrag)) 
  409.         return dragNotAcceptedErr;
  410.  
  411.     // There is only one item, so get its reference number.
  412.     retCode = GetDragItemReferenceNumber(theDrag, 1, &itemRef);
  413.     if (retCode != noErr)
  414.         return retCode;
  415.  
  416.  
  417.     
  418.     // PICT data is preferred, so get it if it's available.
  419.     retCode = GetFlavorDataSize(theDrag, itemRef, 'PICT', &dataSize);
  420.     if (retCode == noErr) {
  421.         tempHandle = TempNewHandle(dataSize, &retCode);
  422.         if (tempHandle == nil) {
  423.             tempHandle = NewHandle(dataSize);
  424.         }
  425.         if (tempHandle != nil) {
  426.             HLock(tempHandle);
  427.             retCode = GetFlavorData(theDrag, itemRef, 'PICT', *tempHandle, 
  428.                                                                     &dataSize, 0);
  429.             if (retCode == noErr) {
  430.                 retCode = SetWindowPicture(theWindow, (PicHandle) tempHandle);
  431.                 if (retCode == noErr)
  432.                     dataObtainedFlag = true;
  433.                     
  434.                 
  435.             }
  436.             DisposeHandle(tempHandle);
  437.         }
  438.     }
  439.  
  440.  
  441.  
  442.     // Check for a Business Card that is *not* in a personal catalog (i.e. somewhere
  443.     // on the users hard disk.
  444.  
  445.     retCode = GetFlavorDataSize(theDrag, itemRef, flavorTypeHFS, &dataSize);
  446.     if (retCode == noErr) 
  447.     {    
  448.         retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, &hfsData, 
  449.                                                                 &dataSize, 0);
  450.         if (retCode == noErr) 
  451.         {            
  452.             if (DoAuthentication() == noErr)
  453.             {
  454.                 name.dataLength = kRStringMaxBytes;
  455.                 type.dataLength = kRStringMaxBytes;
  456.                 OCENewLocalRecordID(&name,&type,&cid,&localRID);
  457.                 OCENewRecordID(&packedRLI,&localRID,&rid);
  458.                 
  459.                 /* Convert a FSSpec to a RecordID */
  460.                 retCode = GetRecordID(&hfsData.fileSpec,
  461.                                     &rid,
  462.                                     OCEGetIndRecordType(kBusinessCardRecTypeNum));
  463.  
  464.                 
  465. /* Now that we have the RecordID, we could easily
  466.     create a DSSpec structure by adding the extension part
  467.     (which is null) as follows:
  468.  
  469.     DSSpec theDSSpec;
  470.     
  471.     theDSSpec.extensionType = kOCEentnDSSpec;
  472.     theDSSpec.extensionSize = 0;
  473.     theDSSpec.extensionValue = NULL;
  474.     theDSSpec.entitySpecifier = &rid;
  475.     
  476.     To create a packedDSSpec from this, we would do the
  477.     following:
  478.  
  479.     PackedDSSpecPtr    thePackedSpecPtr;
  480.     unsigned short packedSpecSize = OCEPackedDSSpecSize(&theDSSpec);                    
  481.     
  482.     thePackedSpecPtr = (PackedDSSpecPtr)NewPtr(packedSpecSize);
  483.     if (thePackedSpecPtr != NULL)
  484.         retCode = OCEPackDSSpec(&theDSSpec, thePackedSpecPtr, packedSpecSize);
  485. */                    
  486.                     
  487.                 if (retCode == noErr)
  488.                 {
  489.                     retCode = OpenPersonalCatalog(rid.rli,
  490.                                                 &dsRefNum);
  491.                     if (retCode == noErr)
  492.                     {
  493.                         retCode = GetAttributeFromRID ( &rid,
  494.                                                     dsRefNum,
  495.                                                     &gWorkPhoneNumber,
  496.                                                     &attribute,
  497.                                                     gIdentity);                
  498.                         if (retCode == noErr)
  499.                         {
  500.                             if (OCEEqualRString((RStringPtr)&gWorkPhoneNumber,
  501.                                                 (RStringPtr)&attribute.attributeType,
  502.                                                 kOCEAttrType) == true)
  503.                                 DrawPhoneNumberAttribute(theWindow,&attribute.value);
  504.                             else
  505.                                 myReportStringInWindow(theWindow,"\pNo Work Phone Number attribute.");
  506.                     
  507.                         }
  508.                     }
  509.                 }
  510.             }
  511.             SysBeep(20);
  512.             SysBeep(20);
  513.             SysBeep(20);
  514.             dataObtainedFlag = true;
  515.             
  516.         }
  517.         else
  518.             DebugStr("\pGetting flavor data for dir failed");
  519.     }
  520.     else
  521.     {
  522.         // Check for items that were dragged from within an AOCE catalog
  523.         
  524.         retCode = GetFlavorDataSize(theDrag, itemRef, flavorTypeDirectory, &dataSize);
  525.         if (retCode == noErr) 
  526.         {
  527.         
  528.             retCode = GetFlavorData(theDrag, itemRef, flavorTypeDirectory, &packedDSSpec, 
  529.                                                                     &dataSize, 0);
  530.             if (retCode == noErr) 
  531.             {
  532.                 retCode = DoAuthentication();
  533.                 if (retCode == noErr)
  534.                 {
  535.             
  536.                 //    In our example, we are only interested in the attribute type
  537.                 //    "aoce PhoneNumber". However, we could retrieve the data from
  538.                 //    any attribute type we want. You can get the standard attribute
  539.                 //    types using the OCEGetIndAttributeType call shown below.
  540.                 //
  541.                 //    theAttrType = OCEGetIndAttributeType(kMailSlotsAttrTypeNum);
  542.                 
  543.                     OCEUnpackDSSpec(&packedDSSpec, &dsspec, &rid);
  544.                     retCode = OpenPersonalCatalog(rid.rli,&dsRefNum);
  545.                     if (retCode == noErr || retCode == kOCEMiscError)
  546.                     {
  547.                         retCode = GetAttributeFromRID ( &rid,
  548.                                                     dsRefNum,
  549.                                                     &gWorkPhoneNumber/*theAttrType*/,
  550.                                                     &attribute,
  551.                                                     gIdentity);
  552.         
  553.                         if (retCode == noErr)
  554.                         {
  555.                             if (OCEEqualRString((RStringPtr)&gWorkPhoneNumber,
  556.                                                 (RStringPtr)&attribute.attributeType,
  557.                                                 kOCEAttrType) == true)
  558.                                 DrawPhoneNumberAttribute(theWindow,&attribute.value);
  559.                             else
  560.                                 myReportStringInWindow(theWindow,"\pNo Work Phone Number attribute.");
  561.                         }
  562.                         else
  563.                             myReportStringInWindow(theWindow,"\pCould not get Work Phone Number attribute.");
  564.                     }
  565.                             
  566.                 }
  567.                 
  568.                 SysBeep(20);
  569.                 SysBeep(20);
  570.                 SysBeep(20);
  571.                 dataObtainedFlag = true;
  572.                 
  573.             }
  574.             else
  575.                 DebugStr("\pGetting flavor data for dir failed");
  576.         }
  577.  
  578.     }
  579.  
  580.  
  581.     if (!dataObtainedFlag) {
  582.         // Couldn't get PICT data so try to get HFS-flavor data.
  583.         dataSize = sizeof(HFSFlavor);
  584.         retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, 
  585.                                                 &theHFSFlavor, &dataSize, 0);
  586.         if (retCode == noErr && theHFSFlavor.fileType == 'PICT') {
  587.             retCode = SetWindowPictureFromFile(&theHFSFlavor.fileSpec, theWindow);
  588.         }
  589.     }
  590. /*
  591.     if (retCode != noErr)
  592.         (void) ReportErrorInWindow(nil,"\pCannot display received picture. ", retCode);
  593. */
  594.  
  595.     return retCode;
  596. }
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606. // *****************************************************************
  607. // *    GetIdentity
  608. // *
  609. // *    authenticate the user
  610. // *****************************************************************
  611. OSErr GetIdentity()
  612. {
  613. OSErr err;
  614. SDPIdentityKind selectedKind;
  615.  
  616.     err = SDPPromptForID(&gIdentity,
  617.                          NULL,
  618.                          NULL,
  619.                          "\pPlease enter the password for your master key",
  620.                          OCEGetIndRecordType(kUserRecTypeNum),
  621.                          kSDPLocalIdentityMask,
  622.                          &selectedKind,
  623.                          NULL,
  624.                          0);   /* ignored */
  625.     return err;
  626. }
  627.  
  628.  
  629. // *****************************************************************
  630. // *    DoAuthentication
  631. // *
  632. // *    check for user authentication
  633. // *****************************************************************
  634. OSErr DoAuthentication()
  635. {
  636. OSErr err;
  637. AuthGetLocalIdentityPB pb;
  638.  
  639.         // first check if the user has already been authenticated. If so
  640.         // we dont want to bother with authenticating again.
  641.     err = AuthGetLocalIdentity((AuthParamBlockPtr)&pb,false);
  642.  
  643.     if (err != noErr)
  644.             // user has not been authenticated, so let's do it now
  645.         err = GetIdentity();
  646.     else
  647.             // user has already been authenticated
  648.         gIdentity = pb.theLocalIdentity;
  649.     
  650.     return err;
  651. }
  652.  
  653. // *****************************************************************
  654. // *    myDrawRString
  655. // *
  656. // *    Hack routine that prints an RString value in a window
  657. // *    
  658. // *****************************************************************
  659.  
  660. myDrawRString(RStringPtr theRString, short *xCoord, short *yCoord)
  661. {
  662. short index;
  663. short byteCount;
  664.  
  665.     index = 0;
  666.     MoveTo(*xCoord,*yCoord);
  667.     while (index < theRString->dataLength)
  668.     {
  669.         byteCount = MaxCharsPerLine;
  670.         if ((theRString->dataLength - index) < MaxCharsPerLine)
  671.             byteCount = (theRString->dataLength - index);
  672.  
  673.         DrawText((Ptr)&theRString->body,index,byteCount);
  674.         index = index + MaxCharsPerLine;
  675.         *yCoord += 10;
  676.         MoveTo(*xCoord,*yCoord);
  677.  
  678.     }
  679.  
  680. }
  681.  
  682. void myReportStringInWindow(WindowPtr theWindow,
  683.                             StringPtr theString)
  684. {
  685.     PicHandle    tempPic;
  686.     GrafPtr        savePort;
  687.     
  688.         GetPort(&savePort);
  689.         SetPort(theWindow);
  690.         
  691.         tempPic = OpenPicture(&theWindow->portRect);
  692.         MoveTo(20, theWindow->portRect.bottom / 3);
  693.         TextFont(systemFont);
  694.         DrawString(theString);
  695.         ClosePicture();
  696.         SetWindowPicture(theWindow, tempPic);
  697.         KillPicture(tempPic);    
  698.         
  699.         SetPort(savePort);    
  700. }
  701.  
  702.  
  703.  
  704. // *****************************************************************
  705. // *    DrawPhoneNumberAttribute
  706. // *
  707. // *    The "aoce PhoneNumber" value data is two RStrings packed
  708. // *    together one right after the other (type followed by the actual number).
  709. // *    This is a hack routine that displays both of the strings.
  710. // *    
  711. // *****************************************************************
  712.  
  713. void DrawPhoneNumberAttribute(WindowPtr theWindow,
  714.                             AttributeValuePtr theAttrValue)
  715. {
  716. RStringPtr valueDataPtr;
  717. StringPtr workStr,phoneNumStr;
  718. Ptr p;
  719.  
  720.     
  721.     valueDataPtr = (RStringPtr)theAttrValue->bytes;
  722.     workStr = OCERToPString(valueDataPtr);
  723.     BlockMove(workStr,&displayStr,*workStr+1);
  724.  
  725.     /* next string is packed right after the first one */
  726.     p = (Ptr)(&valueDataPtr->body[0] + valueDataPtr->dataLength);
  727.     valueDataPtr = (RStringPtr)p;
  728.     phoneNumStr = OCERToPString(valueDataPtr);
  729.  
  730.     ConcatPascalStrings(displayStr, phoneNumStr);
  731.     myReportStringInWindow(theWindow,displayStr);
  732. }
  733.  
  734.  
  735. // OutlineRegion changes a region into a tracing of its border
  736. // which is appropriate for normal dragging
  737. //
  738. // OutlineRegion is called by DoWindowContentDrag
  739.  
  740. void OutlineRegion(RgnHandle theRgn)
  741. {
  742.     RgnHandle tempRgn;
  743.     
  744.     tempRgn = NewRgn();
  745.     CopyRgn(theRgn, tempRgn);
  746.     InsetRgn(tempRgn, 1, 1);
  747.     DiffRgn(theRgn, tempRgn, theRgn);
  748.     DisposeRgn(tempRgn);
  749. }
  750.  
  751.  
  752. // DoWindowContentDrag is called by the application whenever a drag
  753. // begins on one of the app's windows
  754.  
  755. OSErr DoWindowContentDrag(WindowPtr theWindow, EventRecord *theEvent)
  756. {
  757.     OSErr            retCode;
  758.     DragReference    theDrag;
  759.     Rect            dragBounds;
  760.     RgnHandle        dragRgn;
  761.     ItemReference    theItem;
  762.     short            mouseUpModifiers;
  763.     DragAttributes    currDragFlags;
  764.     
  765.     // create a new drag
  766.     retCode = NewDrag(&theDrag);
  767.     if (retCode != noErr) goto Bail;
  768.     
  769.     // use the window ptr as item reference for the heck of it
  770.     theItem = (ItemReference) theWindow;
  771.     
  772.     if ( KeyIsDown(0x37) == false )
  773.     {
  774.         PicHandle        windowPicHandle;
  775.  
  776.         // add the picture data to the drag
  777.         windowPicHandle = GetWindowPicture(theWindow);
  778.         HLock((Handle) windowPicHandle);
  779.         
  780.         retCode = AddDragItemFlavor(theDrag, theItem, 'PICT', 
  781.             (Ptr) *windowPicHandle,
  782.             GetHandleSize((Handle) windowPicHandle), 0);
  783.             
  784.         HUnlock((Handle) windowPicHandle);
  785.     }
  786.     else
  787.     {
  788.         PackedDSSpecPtr    thePackedSpec;
  789.         unsigned short packedSpecSize = OCEPackedDSSpecSize(&gTheCard);
  790.         
  791.         if ( packedSpecSize == 0 )
  792.             DebugStr("\pIt's zero length");
  793.  
  794.         thePackedSpec = (PackedDSSpecPtr)NewPtr(packedSpecSize);
  795.         
  796.         retCode = OCEPackDSSpec(&gTheCard, thePackedSpec, packedSpecSize);
  797.         
  798.         if ( retCode != noErr )
  799.         {
  800.             DebugStr("\pPacking Failed");
  801.             goto DisposeDragAndBail;
  802.         }
  803.         retCode = AddDragItemFlavor(theDrag, theItem, flavorTypeDirectory, (Ptr)&thePackedSpec, kPackedDSSpecMaxBytes, 0);
  804.         if ( retCode != noErr )
  805.         {
  806.             DebugStr("\pAdding Item failed");
  807.             goto DisposeDragAndBail;
  808.         }
  809.     }
  810.     if (retCode != noErr) goto DisposeDragAndBail;
  811.     
  812.     // generate the bounds and region for the drag using the window's
  813.     // content rectangle
  814.     dragBounds = (**((WindowPeek) theWindow)->contRgn).rgnBBox;
  815.     retCode = SetDragItemBounds(theDrag, theItem, &dragBounds);
  816.     if (retCode != noErr) goto DisposeDragAndBail;
  817.     
  818.     dragRgn = NewRgn();
  819.     RectRgn(dragRgn, &dragBounds);
  820.     OutlineRegion(dragRgn);
  821.     
  822.     // do the drag and clean up
  823.     retCode = TrackDrag(theDrag, theEvent, dragRgn);
  824.     
  825.     DisposeRgn(dragRgn);
  826.     
  827.     if (retCode == noErr) {
  828.         
  829.         // the drag was successful
  830.         
  831.         // if the option key was not pressed at mouseUp and the drag ended
  832.         // in the source application then this is a move operation and we
  833.         // have to clear the source window
  834.         
  835.         (void) GetDragModifiers(theDrag, nil, nil, &mouseUpModifiers);
  836.                 
  837.         (void) GetDragAttributes(theDrag, &currDragFlags);
  838.     
  839.         if ((mouseUpModifiers & optionKey) == 0 &&
  840.             (currDragFlags & dragInsideSenderApplication) != 0)
  841.             
  842.             (void) SetEmptyWindowPicture(theWindow);
  843.     }
  844.     
  845. DisposeDragAndBail:
  846.     DisposeDrag(theDrag);
  847.     
  848. Bail:
  849.     return retCode;
  850. }
  851.  
  852.  
  853.  
  854. /***************************************************
  855.  *  Apple Event routines
  856.  *
  857.  *  These routines handle the required Apple events
  858.  ***************************************************/
  859.  
  860. pascal OSErr DoAEOpenApplication(AppleEvent * theAppleEvent,
  861.                                  AppleEvent * replyAppleEvent, 
  862.                                  long refCon)
  863. {
  864. #pragma unused (theAppleEvent, replyAppleEvent, refCon)
  865.  
  866.     // make an empty window
  867.     (void) DoNewWindow();
  868.     return noErr;
  869. }
  870.  
  871. pascal OSErr DoAEOpenDocuments(AppleEvent * theAppleEvent,
  872.                                AppleEvent * replyAppleEvent, 
  873.                                long refCon)
  874. {
  875. #pragma unused (replyAppleEvent, refCon)
  876.     OSErr        retCode;
  877.     FSSpec        currSpec;
  878.     AEDescList    docDescList;
  879.     long        itemCount, index;
  880.     AEKeyword    keyword;
  881.     DescType    typeCode;
  882.     Size        actualSize;
  883.     
  884.     // retrieve all documents from the Apple event and open them
  885.     retCode = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList,
  886.         &docDescList);
  887.     if (retCode != noErr) goto Bail;
  888.     
  889.     retCode = AECountItems(&docDescList, &itemCount);
  890.     if (retCode != noErr) goto DisposeDocDescListAndBail;
  891.  
  892.      for (index = 1; index <= itemCount; index++) {
  893.          retCode = AEGetNthPtr(&docDescList, index, typeFSS,
  894.              &keyword, &typeCode, (Ptr) &currSpec, sizeof(FSSpec),
  895.              &actualSize);
  896.          if (retCode != noErr) goto DisposeDocDescListAndBail;
  897.          
  898.          (void) OpenPictureInNewWindow(&currSpec);
  899.      }
  900.      
  901.  DisposeDocDescListAndBail:
  902.      (void) AEDisposeDesc(&docDescList);
  903.      
  904.  Bail:
  905.      if (retCode == noErr) return noErr;
  906.      else return errAEEventNotHandled;
  907. }
  908.  
  909. pascal OSErr DoAEQuitApplication(AppleEvent * theAppleEvent,
  910.                                  AppleEvent * replyAppleEvent, 
  911.                                  long refCon)
  912. {
  913. #pragma unused (theAppleEvent, replyAppleEvent, refCon)
  914.  
  915.     DoQuit();     // set the quit flag (doesn't immediately quit)
  916.     return noErr;
  917. }
  918.  
  919. void DoHighLevelEvent(EventRecord * theEventRecPtr)
  920. // high-level event dispatching
  921. {
  922.     (void) AEProcessAppleEvent(theEventRecPtr);
  923. }
  924.  
  925. OSErr InstallAppleEventHandlers()
  926. {
  927.     OSErr retCode;
  928.     
  929.     retCode = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
  930.                 /*(AEEventHandlerProcPtr)*/(EventHandlerProcPtr) DoAEOpenApplication, 0, false);
  931.                                     
  932.     if (retCode == noErr)
  933.         retCode = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  934.                 /*(AEEventHandlerProcPtr)*/(EventHandlerProcPtr) DoAEOpenDocuments, 0, false);
  935.  
  936.     if (retCode == noErr)
  937.         retCode = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  938.                 /*(AEEventHandlerProcPtr)*/(EventHandlerProcPtr) DoAEQuitApplication, 0, false);
  939.     
  940.     return retCode;
  941. }
  942.  
  943.  
  944. /***************************************************
  945.  *   general application utility routines
  946.  ***************************************************/
  947.  
  948. // ConcatPascalStrings concatenates s2 to the end of s1
  949. void ConcatPascalStrings(StringPtr s1, StringPtr s2)
  950. {
  951.     short s1Length, s2Length;
  952.     
  953.     s1Length = s1[0];
  954.     s2Length = s2[0];
  955.     BlockMove(&s2[1], &s1[s1Length+1], s2Length);
  956.     s1[0] = s1Length + s2Length;
  957. }
  958.  
  959. // GetApplicationName uses the Process Manager to find
  960. // the current app's name
  961. OSErr GetApplicationName(StringPtr appNameString)
  962. {
  963.     ProcessInfoRec        appPIR;
  964.     ProcessSerialNumber    appPSN;
  965.     
  966.     appPSN.lowLongOfPSN = kCurrentProcess;
  967.     appPSN.highLongOfPSN = 0;
  968.     
  969.     appPIR.processInfoLength = sizeof(ProcessInfoRec);
  970.     appPIR.processAppSpec = nil;
  971.     appPIR.processName = appNameString;
  972.     
  973.     return GetProcessInformation(&appPSN, &appPIR);
  974. }
  975.  
  976.  
  977. /***************************************************
  978.  *  routines for dealing with the window pictures
  979.  ***************************************************/
  980.  
  981. // GetWindowPicture returns the handle of a window's picture
  982.  
  983. PicHandle GetWindowPicture(WindowPtr theWindow)
  984. {
  985.     WindowDataHandle    windowData;
  986.  
  987.     windowData = (WindowDataHandle) GetWRefCon(theWindow);
  988.     return (**windowData).windowPic;
  989. }
  990.  
  991.  
  992. // SetWindowPicture copies thePicture into the existing windowPic
  993. // handle of theWindow's data.  If the copy is successful,
  994. // the window is invalidated to force it to be redrawn
  995.  
  996. OSErr SetWindowPicture(WindowPtr theWindow, PicHandle newPicture)
  997. {
  998.     PicHandle    windowPic;
  999.     Size        picSize;
  1000.     GrafPtr        savePort;
  1001.     OSErr        retCode;
  1002.     
  1003.     // get the old picture handle
  1004.     windowPic = GetWindowPicture(theWindow);
  1005.     
  1006.     // resize the old handle to hold the new picture
  1007.     picSize = GetHandleSize((Handle) newPicture);
  1008.     SetHandleSize((Handle) windowPic, picSize);
  1009.     retCode = MemError();
  1010.     if (retCode == noErr) {
  1011.     
  1012.         // copy the picture and invalidate the window
  1013.         BlockMove(*newPicture, *windowPic, picSize);
  1014.         
  1015.         GetPort(&savePort);
  1016.         SetPort(theWindow);
  1017.         InvalRect(&theWindow->portRect);
  1018.         SetPort(savePort);
  1019.     }
  1020.     return retCode;
  1021. }
  1022.  
  1023.  
  1024. // SetEmptyWindowPicture replaces the existing picture handle
  1025. // for a window with a new, empty one
  1026.  
  1027. OSErr SetEmptyWindowPicture(WindowPtr theWindow)
  1028. {
  1029.     PicHandle emptyPicture;
  1030.     
  1031.     // make a new, empty picture handle
  1032.     emptyPicture = (PicHandle) NewHandleClear(sizeof(Picture));
  1033.     
  1034.     if (emptyPicture != nil)
  1035.     
  1036.         // replace the window's picture with the empty picture
  1037.         return SetWindowPicture(theWindow, emptyPicture);
  1038.         
  1039.     else
  1040.         return MemError();
  1041. }
  1042.  
  1043.  
  1044. // SetWindowPictureFromFile reads the PICT file specified by pictSpec
  1045. // and replaces the window's picture with the new one
  1046.  
  1047. OSErr SetWindowPictureFromFile(FSSpecPtr pictSpec, WindowPtr theWindow)
  1048. {
  1049.     OSErr        retCode;
  1050.     short        pictRefNum;
  1051.     long        fileLength;
  1052.     Size        pictSize;
  1053.     Handle        tempHandle;
  1054.     
  1055.     pictRefNum = 0;
  1056.     tempHandle = nil;
  1057.     
  1058.     // open the file and find its size
  1059.     retCode = FSpOpenDF(pictSpec, fsRdPerm, &pictRefNum);
  1060.     if (retCode != noErr) goto Bail;
  1061.     
  1062.     retCode = GetEOF(pictRefNum, &fileLength);
  1063.     if (retCode != noErr) goto Bail;
  1064.     
  1065.     // skip over 512-byte pict file header
  1066.     retCode = SetFPos(pictRefNum, fsFromMark, 512);
  1067.     if (retCode != noErr) goto Bail;
  1068.  
  1069.     pictSize = fileLength - 512;
  1070.     
  1071.     // allocate a buffer for the file's picture data,
  1072.     // in temp memory if it is available
  1073.     tempHandle = TempNewHandle(pictSize, &retCode);
  1074.     if (tempHandle == nil) {
  1075.         tempHandle = NewHandle(pictSize);
  1076.         retCode = MemError();
  1077.     }
  1078.     if (tempHandle == nil) goto Bail;
  1079.     
  1080.     // read in the picture data
  1081.     HLock(tempHandle);
  1082.     retCode = FSRead(pictRefNum, &pictSize, *tempHandle);
  1083.     HUnlock(tempHandle);
  1084.     if (retCode != noErr) goto Bail;
  1085.     
  1086.     // replace the window's picture with the new data
  1087.     retCode = SetWindowPicture(theWindow, (PicHandle) tempHandle);
  1088.     
  1089. Bail:
  1090.     if (pictRefNum != 0) FSClose(pictRefNum);
  1091.     if (tempHandle != nil) DisposeHandle(tempHandle);
  1092.     
  1093.     return retCode;
  1094. }
  1095.  
  1096.  
  1097. // OpenPictureInNewWindow creates a new window and sets its
  1098. // picture to be the one contained in the specified PICT file
  1099. // If the file cannot be read, an error message is displayed
  1100. // in the window instead
  1101.  
  1102. WindowPtr OpenPictureInNewWindow(FSSpecPtr fileSpec)
  1103. {
  1104.     WindowPtr    theWindow;
  1105.     OSErr                retCode;
  1106.     
  1107.     theWindow = DoNewWindow();
  1108.     if (theWindow != nil) {
  1109.     
  1110.         retCode = SetWindowPictureFromFile(fileSpec, theWindow);
  1111.         if (retCode != noErr) {
  1112.             (void) ReportErrorInWindow(theWindow,
  1113.                 "\pCannot display opened picture. ", retCode);
  1114.         }
  1115.     }
  1116.     return theWindow;
  1117. }
  1118.  
  1119.  
  1120. // DrawWindow draws a window's picture in the window
  1121.  
  1122. void DrawWindow(WindowPtr theWindow)
  1123. {
  1124.     PicHandle    windowPic;
  1125.     Rect        tempRect;
  1126.     
  1127.     windowPic = GetWindowPicture(theWindow);
  1128.     
  1129.     if (windowPic != nil) {
  1130.         tempRect = (**windowPic).picFrame;
  1131.         DrawPicture(windowPic, &tempRect);
  1132.     }
  1133. }
  1134.  
  1135. // ReportErrorInWindow draws a string and a number in the specified window
  1136. // if theWindow is nil, a new window is created and its WindowPtr is returned
  1137.  
  1138. WindowPtr ReportErrorInWindow(WindowPtr theWindow, StringPtr theString,
  1139.     OSErr errNum)
  1140. {
  1141.     Str255     copyStr;
  1142.     Str15    numStr;
  1143.     
  1144.     BlockMove(theString, copyStr, theString[0]+1);
  1145.     NumToString(errNum, numStr);
  1146.     ConcatPascalStrings(copyStr, numStr);
  1147.     return ReportStringInWindow(theWindow, copyStr);
  1148. }
  1149.  
  1150. // ReportStringInWindow draws a string in the specified window
  1151. // if theWindow is nil, a new window is created and its WindowPtr is returned
  1152.  
  1153. WindowPtr ReportStringInWindow(WindowPtr theWindow, StringPtr theString)
  1154. {
  1155.     PicHandle    tempPic;
  1156.     GrafPtr        savePort;
  1157.     
  1158.     if (theWindow == nil)
  1159.         theWindow = DoNewWindow();
  1160.     
  1161.     if (theWindow != nil) {
  1162.         GetPort(&savePort);
  1163.         SetPort(theWindow);
  1164.         
  1165.         tempPic = OpenPicture(&theWindow->portRect);
  1166.         MoveTo(20, theWindow->portRect.bottom / 3);
  1167.         TextFont(systemFont);
  1168.         DrawString(theString);
  1169.         ClosePicture();
  1170.         SetWindowPicture(theWindow, tempPic);
  1171.         KillPicture(tempPic);    
  1172.         
  1173.         SetPort(savePort);    
  1174.     }
  1175.     return theWindow;
  1176. }
  1177.  
  1178.  
  1179. /***************************************************
  1180.  *  typical Mac toolbox routines
  1181.  ***************************************************/
  1182.  
  1183. // CreateMenus makes menus the old-fashioned way
  1184. void CreateMenus()
  1185. {
  1186.     // create Apple menu
  1187.     gAppleMenuHandle = NewMenu(kAppleMenuID, "\p\024");
  1188.     AppendMenu(gAppleMenuHandle, "\pAbout SimpleDrag...;(-");
  1189.     AddResMenu(gAppleMenuHandle, 'DRVR');
  1190.     InsertMenu(gAppleMenuHandle, 0);
  1191.  
  1192.     // create File menu
  1193.     gFileMenuHandle = NewMenu(kFileMenuID, "\pFile");
  1194.     AppendMenu(gFileMenuHandle, "\pNew/N;Open.../O;Close/W;(-;Quit/Q");
  1195.     InsertMenu(gFileMenuHandle, 0);
  1196.     
  1197.     DrawMenuBar();
  1198. }
  1199.  
  1200. // DoOpen displays a standard file dialog and, if the user selects
  1201. // a PICT file, opens the file in a new window
  1202. void DoOpen()
  1203. {
  1204.     StandardFileReply    fileSFR;
  1205.     SFTypeList            sfTypes;
  1206.     
  1207.     sfTypes[0] = 'PICT';
  1208.     
  1209.     StandardGetFile(nil, 1, sfTypes, &fileSFR);
  1210.     if (fileSFR.sfGood)
  1211.         (void) OpenPictureInNewWindow(&fileSFR.sfFile);
  1212. }
  1213.  
  1214.  
  1215. // DoNewWindow creates a new window with an empty picture
  1216. // and returns the window's WindowPtr
  1217.  
  1218. WindowPtr DoNewWindow()
  1219. {
  1220.     WindowPtr            newWindow;
  1221.     Str63                windowNameStr;
  1222.     Str15                numStr;
  1223.     WindowDataHandle    newWindowDataHandle;
  1224.     Rect                windowRect;
  1225.     OSErr                retCode;
  1226.     
  1227.     // one more window in the world
  1228.     gWindowCounter++;
  1229.     
  1230.     // find a size and place for the new window
  1231.     windowRect = qd.screenBits.bounds;
  1232.     SetRect(&windowRect, windowRect.left, windowRect.top + 40,
  1233.         windowRect.right / 2, windowRect.bottom / 2);
  1234.     OffsetRect(&windowRect, 20 * (gWindowCounter % 10), 20 * (gWindowCounter % 10));
  1235.  
  1236.     // make a name for the window by concatenating gWindowCounter to the app name
  1237.     NumToString(gWindowCounter, numStr);
  1238.     if (GetApplicationName(windowNameStr) != noErr)
  1239.         *windowNameStr = 0;
  1240.     ConcatPascalStrings(windowNameStr, "\p ");
  1241.     ConcatPascalStrings(windowNameStr, numStr);
  1242.     
  1243.     // open the window
  1244.     if (gHasColorQuickdrawFlag)
  1245.         newWindow = NewCWindow(nil, &windowRect, windowNameStr, true,
  1246.             documentProc, (WindowPtr) -1, true, 0);
  1247.     else
  1248.         newWindow = NewWindow(nil, &windowRect, windowNameStr, true,
  1249.             documentProc, (WindowPtr) -1, true, 0);
  1250.     
  1251.     if (newWindow == nil) goto Bail;
  1252.     
  1253.     SetPort(newWindow);
  1254.     ClipRect(&newWindow->portRect);
  1255.     
  1256.     // attach my drag handlers to this window
  1257.     
  1258.     if ((retCode = InstallDragHandlers(newWindow)) != noErr)
  1259.     {
  1260.         if ( retCode == duplicateHandlerErr )
  1261.             RemoveDragHandlers(newWindow);
  1262.         goto DisposeWindowAndBail;
  1263.     }
  1264.     // allocate a data structure and a blank picture for the window
  1265.     
  1266.     newWindowDataHandle = (WindowDataHandle) NewHandle(sizeof(WindowData));
  1267.     if (newWindowDataHandle == nil) goto RemoveHandlersAndBail;
  1268.  
  1269.     (**newWindowDataHandle).windowPic = 
  1270.         (PicHandle) NewHandleClear(sizeof(Picture));
  1271.     if ((**newWindowDataHandle).windowPic == nil) {
  1272.         DisposeHandle((Handle) newWindowDataHandle);
  1273.         goto RemoveHandlersAndBail;
  1274.     }
  1275.     
  1276.     SetWRefCon(newWindow, (long) newWindowDataHandle);
  1277.         
  1278.     return newWindow;
  1279.  
  1280. RemoveHandlersAndBail:
  1281.     RemoveDragHandlers(newWindow);
  1282.     
  1283. DisposeWindowAndBail:
  1284.     DisposeWindow(newWindow);
  1285.     
  1286. Bail:
  1287.     gWindowCounter--;
  1288.     return nil;
  1289.     
  1290. }
  1291.  
  1292. // DoCloseWindow disposes of a window and does all necessary clean-up
  1293. void DoCloseWindow(WindowPtr theWindow)
  1294. {
  1295.     if (theWindow != nil) {
  1296.         KillPicture(GetWindowPicture(theWindow));
  1297.         DisposeHandle((Handle) GetWRefCon(theWindow));
  1298.         RemoveDragHandlers(theWindow);
  1299.         DisposeWindow(theWindow);
  1300.     }
  1301. }
  1302.  
  1303. // DoQuit closes all open windows and sets the global quit flag
  1304. void DoQuit()
  1305. {
  1306.     while (FrontWindow() != nil)
  1307.         DoCloseWindow(FrontWindow());
  1308.     gQuitFlag = true;
  1309. }
  1310.  
  1311. // DoAboutWindow just raises a new window and displays my name
  1312. WindowPtr DoAboutWindow()
  1313. {
  1314.     return ReportStringInWindow(nil, "\pSimpleDrag by Greg Robbins   July 1993");    
  1315. }
  1316.  
  1317. // DoMenuCommand handles user menu selections
  1318. void DoMenuCommand(long menuVal)
  1319. {
  1320.     short        theItem, theMenu;
  1321.     Str255        deskAccessoryName;
  1322.     
  1323.     theItem = LoWord(menuVal);
  1324.     theMenu = HiWord(menuVal);
  1325.  
  1326.     switch (theMenu) {
  1327.  
  1328.         case kAppleMenuID:
  1329.             if (theItem == kAboutMenuItem)
  1330.                 (void) DoAboutWindow();
  1331.                 
  1332.             else {
  1333.                 GetItem(gAppleMenuHandle, theItem, deskAccessoryName);
  1334.                 (void) OpenDeskAcc(deskAccessoryName);
  1335.             }
  1336.             break;
  1337.  
  1338.         case kFileMenuID:
  1339.  
  1340.             if (theItem == kNewMenuItem)
  1341.                 (void) DoNewWindow();
  1342.  
  1343.             else if (theItem == kOpenMenuItem)
  1344.                 DoOpen();
  1345.             
  1346.             else if (theItem == kCloseMenuItem)
  1347.                 DoCloseWindow(FrontWindow());
  1348.                 
  1349.             else if (theItem == kQuitMenuItem)
  1350.                 DoQuit();
  1351.                 
  1352.             break;
  1353.  
  1354.     }
  1355.     HiliteMenu(0);      // unhilight menu title
  1356. }
  1357.  
  1358.  
  1359. /***************************************************
  1360.  *  finally, the main program and event loop
  1361.  ***************************************************/
  1362.  
  1363. main()
  1364. {
  1365.     OSErr        retCode;
  1366.     long        gestResponse;
  1367.     Boolean        canRunFlag;
  1368.     
  1369.     
  1370.     // initialize the toolbox
  1371.     InitGraf(&qd.thePort);
  1372.     InitFonts();
  1373.     InitWindows();
  1374.     InitMenus();
  1375.     TEInit();
  1376.     InitDialogs(nil);
  1377.     InitCursor();
  1378.     FlushEvents(everyEvent,0);
  1379.     MaxApplZone();
  1380.     
  1381.     // can we run?  let's be optimistic
  1382.     canRunFlag = true;
  1383.     
  1384.     // are the Apple Event and Drag managers available?
  1385.     // they simply must be
  1386.     
  1387.     retCode = Gestalt(gestaltAppleEventsAttr, &gestResponse);
  1388.     if (retCode != noErr ||
  1389.         (gestResponse & (1 << gestaltAppleEventsPresent)) == 0)
  1390.         
  1391.         canRunFlag = false;
  1392.  
  1393.     retCode = Gestalt(gestaltDragMgrAttr, &gestResponse);
  1394.     if (retCode != noErr ||
  1395.         (gestResponse & (1 << gestaltDragMgrPresent)) == 0)
  1396.         
  1397.         canRunFlag = false;
  1398.  
  1399.     if (!canRunFlag) ExitToShell();  // an alert would be nicer
  1400.     
  1401.     
  1402.     // use Gestalt to find out what the world is like
  1403.     // in particular, check for Color QuickDraw
  1404.     
  1405.     retCode = Gestalt(gestaltQuickdrawVersion, &gestResponse);
  1406.     if (retCode != noErr || gestResponse < 0x0100)
  1407.         gHasColorQuickdrawFlag = false;
  1408.     else
  1409.         gHasColorQuickdrawFlag = true;
  1410.  
  1411.  
  1412.     // now let's initialize everything and install the
  1413.     // drag and Apple event handlers
  1414.  
  1415.     // initialize application globals
  1416.     
  1417.     gQuitFlag = false;
  1418.     gWindowCounter = 0;
  1419.     
  1420.     // install Apple event handlers
  1421.     (void) InstallAppleEventHandlers();
  1422.     
  1423.     // make the menus
  1424.     CreateMenus();
  1425.  
  1426.     // authenticate the user
  1427.     DoAuthentication();
  1428.  
  1429.     // main event loop
  1430.     
  1431.     while (!gQuitFlag) {
  1432.  
  1433.         ProcessEvents();
  1434.  
  1435.     }
  1436.     
  1437.     // Good night
  1438. }
  1439.  
  1440.  
  1441. void ProcessEvents(void)
  1442. {
  1443.     EventRecord    mainEventRec;
  1444.     Boolean        eventFlag;
  1445.     
  1446.     WindowPtr    whichWindow;
  1447.     Rect        tempRect;
  1448.  
  1449.     eventFlag = WaitNextEvent(everyEvent, &mainEventRec, 60*60*60, nil);
  1450.     
  1451.     switch(mainEventRec.what) {
  1452.     
  1453.         case mouseDown:
  1454.             switch (FindWindow(mainEventRec.where, &whichWindow)) {
  1455.  
  1456.                 case inSysWindow:  // desk accessory window
  1457.                     SystemClick(&mainEventRec, whichWindow);
  1458.                     break;
  1459.                     
  1460.                 case inMenuBar:
  1461.                     DoMenuCommand(MenuSelect(mainEventRec.where));
  1462.                     break;
  1463.                     
  1464.                 case inDrag:
  1465.                     tempRect = qd.screenBits.bounds;
  1466.                     DragWindow(whichWindow, mainEventRec.where, &tempRect);
  1467.                     break;
  1468.                     
  1469.                 case inGoAway:
  1470.                     if (TrackGoAway(whichWindow, mainEventRec.where))
  1471.                         DoCloseWindow(whichWindow);
  1472.                     break;
  1473.                     
  1474.                 case inContent:
  1475.                 
  1476.                     // check to see if the user is starting a drag
  1477.                     if (WaitMouseMoved(mainEventRec.where))
  1478.                         
  1479.                         // if so, do the drag magic
  1480.                         DoWindowContentDrag(whichWindow, &mainEventRec);
  1481.                         
  1482.                     else if (whichWindow != FrontWindow())
  1483.                         SelectWindow(whichWindow);
  1484.                     break;
  1485.             }
  1486.             break;
  1487.  
  1488.         case updateEvt:
  1489.         
  1490.             whichWindow = (WindowPtr) mainEventRec.message;
  1491.         
  1492.             if ( ((WindowPeek)whichWindow)->windowKind != dialogKind )
  1493.             {
  1494.                 SetPort(whichWindow);
  1495.                 BeginUpdate(whichWindow);
  1496.                 
  1497.                 EraseRect(&whichWindow->portRect);
  1498.                 DrawWindow(whichWindow);
  1499.                 
  1500.                 EndUpdate(whichWindow);
  1501.             }
  1502.             break;
  1503.                     
  1504.         case keyDown:
  1505.         case autoKey:
  1506.             if (mainEventRec.modifiers & cmdKey)
  1507.                 DoMenuCommand(MenuKey(mainEventRec.message & charCodeMask));
  1508.             break;
  1509.             
  1510.         case kHighLevelEvent:
  1511.             DoHighLevelEvent(&mainEventRec);
  1512.             break;
  1513.         
  1514.         // a real app should handle all of these events.
  1515.         // Since the code is in Inside Mac:Mac Toolbox Essentials,
  1516.         // you really have no excuse for not supporting all the
  1517.         // standard low-level events
  1518.         
  1519.         
  1520.         
  1521.         // however, this is just a sample program, so I have an excuse
  1522.         
  1523.         case activateEvt:
  1524.         case osEvt:
  1525.         case diskEvt:
  1526.         case mouseUp:
  1527.             break;
  1528.     }
  1529. }
  1530.  
  1531.  
  1532.  
  1533.  
  1534. /*******************************************************************************
  1535. ** 
  1536. ** Keith Rollin's utility for using GetKeys from C
  1537. ** returns true if the Key with the given KeyCode is down
  1538. */
  1539. #pragma segment Main
  1540. Boolean KeyIsDown(short keyCode)
  1541. {
  1542.     union {
  1543.         KeyMap asMap;
  1544.         unsigned char asBytes[16];
  1545.     } myMap;
  1546.  
  1547.     GetKeys(myMap.asMap);
  1548.     return ((myMap.asBytes[keyCode >> 3] >> (keyCode & 0x07)) & 1) != 0;
  1549. }
  1550.  
  1551.